﻿/////////////////////////////////////////////////////////////////////////
//                                                                     //
//    MTGProject - A Magic The Gathering Networked Environment         //
//                                                                     //
//      Copyright (c) 2008-2009 by The MTGProject Team (CSC230)        //
//                                                                     //
// This file is part of MTGProject.                                    //
//                                                                     //
// MTGProject is free software; you can redistribute it and/or         //
// modify it under the terms of the GNU Lesser General Public          //
// License as published by the Free Software Foundation; either        //
// version 3 of the License, or (at your option) any later version.    //
//                                                                     //
// This library is distributed in the hope that it will be useful,     //
// but WITHOUT ANY WARRANTY; without even the implied warranty of      //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the       //
// GNU Lesser General Public License for more details.                 //
//                                                                     //
// You should have received a copy of the GNU Lesser General Public    //
// License along with this library; if not, write to the Free Software //
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA           //
// 02111-1307, USA, or contact the author(s):                          //
//                                                                     //
// Ruben Acuna <flyingfowlsoftware@earthlink.net>                      //
//                                                                     //
/////////////////////////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Text;

namespace MTGProject
{
    public class Player
    {
        #region variables

        private CardPool permanents;
        private string name;
        private CardPool deck;
        private CardPool graveyard;
        private CardPool hand;
        private LinkedList<ManaColor> manaPool;
        private Player enemy;
        private PlayerController puppetMaster;

        private int health;

        #endregion

        #region properties

        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        public CardPool Permanents
        {
            get { return permanents; }
            set { permanents = value; }
        }

        public CardPool Deck
        {
            get { return deck; }
            set { deck = value; }
        }

        public CardPool Graveyard
        {
            get { return graveyard; }
            set { graveyard = value; }
        }

        public CardPool Hand
        {
            get { return hand; }
            set { hand = value; }
        }

        public LinkedList<ManaColor> ManaPool
        {
            get { return manaPool; }
            set { manaPool = value; }
        }

        public int Health
        {
            get { return health; }
            set { health = value; }
        }

        public Player Enemy
        {
            get { return enemy; }
            set { enemy = value; }
        }

        public PlayerController PuppetMaster
        {
            get { return puppetMaster; }
            set { puppetMaster = value; }
        }
         
        #endregion

        #region consturctor

        public Player(string name)
        {
            Name = name;
            Deck = new CardPool(Zone.DECK);
            Graveyard = new CardPool(Zone.GRAVEYARD);
            ManaPool = new LinkedList<ManaColor>();
            Hand = new CardPool(Zone.HAND);
            Health = 20;
            Permanents = new CardPool(Zone.PERMANENTS);
            Enemy = null;
            puppetMaster = null;
        }

        #endregion

        #region methods

        public void TapCard(IPermanent card)
        {
            if (!card.IsTapped && permanents.HasCard(card))
            {
                card.IsTapped = true;

                card.OnTap(); //SCRIPT HOOK

                if (card is CardLand)
                    System.Console.WriteLine("  " + Name + " taps a " + card.Name + " for a " + card.Colors.First.Value + " mana.");
                else if (card is CardCreature)
                    System.Console.WriteLine(Name + "attempted to attack with" + card.Name + " during a non-combat phase.");
            }
            else
                System.Console.WriteLine(Name + " attempted to tap already tapped card or card not in play.");

        }

        public void AttackWithCard(CardCreature card)
        {
            int damage = card.DealDamage();

            System.Console.WriteLine("  " + Name + " attacks " + Enemy.Name + " with " + ((CardCreature)card).Name + " and deals " + damage + " damage.");

            //Keyword: VIGILANCE (complete)
            if (!card.HasKeyword(CreatureKeyword.VIGILANCE))
                card.IsTapped = true;

            //Keyword: LIFELINK (probably complete)
            if (card.HasKeyword(CreatureKeyword.LIFELINK))
                Heal(damage, card);

                enemy.TakeDamage(card.DealDamage(), card);
        }

        public void TapCardByName(string name)
        {
            IPermanent card = null;

            foreach (IPermanent permanent in Permanents.Cards)
            {
                if (permanent.Name.ToLower().Equals(name.ToLower()) && permanent.IsTapped == false)
                {
                    card = permanent;
                }
            }

            if (card != null)
                TapCard(card);
            else
                System.Console.WriteLine(Name + " attempted to tap a card by name that did not exist.");
        }

        public void PlayCard(ICard card)
        {
            if (Hand.HasCard(card))
            {
                if (UtilMagic.CanAffordCost(card.Cost, ManaPool))
                {
                    card.StartScript(puppetMaster);

                    Hand.RemoveCard(card);

                    UtilMagic.PayCost(card.Cost, ManaPool);
                    card.OnPayCost(); //SCRIPT HOOK

                    if (card is IPermanent)
                    {
                        if (!(card is CardEnchantment && !(((CardEnchantment)card).Type == EnchantmentType.GLOBAL)))
                        {
                            Permanents.AddCard(card);
                            card.OnResolve(); //SCRIPT HOOK
                        }
                        else
                        {
                            //we just played a enchantment that is an aura
                            throw new Exception("Attempted to play an aura enchantment.");
                        }
                    }
                    else if (card is CardSorcery)
                    {
                        card.OnResolve(); //SCRIPT HOOK
                        Graveyard.AddCard(card);
                    }
                    else
                        throw new Exception("Attempted to play unknown card type.");

                    System.Console.WriteLine("  " + Name + " plays " + card.Name + ".");

                }
                else
                    System.Console.WriteLine(Name + " attempted to play card without paying mana.");
            }
            else
                System.Console.WriteLine(Name + " attempted to play a card not in their hand.");
        }

        public void TakeDamage(int amount, object cause)
        { 
            health -= Math.Abs(amount);

            puppetMaster.Tell("You lose " + amount + " health.");
        }

        public void Heal(int amount, object cause)
        {
            health += Math.Abs(amount);

            puppetMaster.Tell("You gain " + amount + " health.");
        }

        #endregion
    }
}
